﻿#include "buffer.h"

Buffer::Buffer() : m_read_step(0), m_write_step(0), m_buffer(BUFFER_DEFAULT_SIZE, 0)
{
}

char *Buffer::begin()
{
    return &(*m_buffer.begin());
}

uint64_t Buffer::getHeadSpace()
{
    return m_read_step;
}

uint64_t Buffer::getTailSpace()
{
    return m_buffer.size() - m_write_step;
}

uint64_t Buffer::getTotalSpace()
{
    return getHeadSpace() + getTailSpace();
}

void Buffer::ensureWriteSpace(uint64_t size)
{
    if (size <= getTailSpace())
    {
        return;
    }
    else if (size <= getTotalSpace())
    {
        std::copy(getReadAddr(), getReadAddr() + getReadSize(), begin());
        m_write_step = getReadSize();
        m_read_step = 0;
    }
    else
    {
        m_buffer.resize(m_write_step + size + 10);
    }
}

void Buffer::moveReadStep(uint64_t size)
{
    if (size == 0)
        return;
    assert(size <= getReadSize());
    m_read_step += size;
}

void Buffer::moveWriteStep(uint64_t size)
{
    if (size == 0)
        return;
    assert(size <= getTailSpace());
    m_write_step += size;
}

uint64_t Buffer::getReadSize()
{
    return m_write_step - m_read_step;
}

char *Buffer::getWriteAddr()
{
    return begin() + m_write_step;
}

char *Buffer::getReadAddr()
{
    return begin() + m_read_step;
}

void Buffer::write(const void *data, uint64_t size)
{
    if (size == 0)
        return;
    ensureWriteSpace(size);
    const char *d = static_cast<const char *>(data);
    std::copy(d, d + size, getWriteAddr());
    moveWriteStep(size);
}

void Buffer::writeString(const std::string &data)
{
    return write(data.c_str(), data.size());
}

void Buffer::writeBuffer(Buffer &data)
{
    return write(data.getReadAddr(), data.getReadSize());
}

void Buffer::read(void *buffer, uint64_t size)
{
    assert(size <= getReadSize());
    std::copy(getReadAddr(), getReadAddr() + size, (char *)buffer);
    moveReadStep(size);
}

std::string Buffer::readString(uint64_t size)
{
    assert(size <= getReadSize());
    std::string str;
    str.resize(size);
    read(&str[0], size);
    return str;
}

std::string Buffer::readLineString()
{
    char *pos = (char *)memchr(getReadAddr(), '\n', getReadSize());
    if (pos == nullptr)
    {
        return "";
    }
    return readString(pos - getReadAddr() + 1);
}

void Buffer::clear()
{
    m_buffer.clear();
    m_read_step = 0;
    m_write_step = 0;
}